package com.bwda.dsrs.filecenter.service.impl;

import com.bwda.dsrs.base.centerbase.response.ResponseEntity;
import com.bwda.dsrs.base.util.CopyUtil;
import com.bwda.dsrs.filecenter.domain.BusinessConstants;
import com.bwda.dsrs.filecenter.domain.condition.sensitivelevel.SensitiveLevelCondition;
import com.bwda.dsrs.filecenter.domain.condition.sensitiverule.SensitiveRuleCondition;
import com.bwda.dsrs.filecenter.domain.exception.BusinessServiceException;
import com.bwda.dsrs.filecenter.domain.form.sensitivelevel.SensitiveLevelUpdateForm;
import com.bwda.dsrs.filecenter.domain.form.sensitiverule.SensitiveRuleCreateForm;
import com.bwda.dsrs.filecenter.domain.po.sensitivelevel.SensitiveLevelPo;
import com.bwda.dsrs.filecenter.domain.po.sensitiverule.SensitiveRulePo;
import com.bwda.dsrs.filecenter.domain.po.sensitivewords.SensitiveWordsPo;
import com.bwda.dsrs.filecenter.domain.vo.sensitiverule.SensitiveRuleVo;
import com.bwda.dsrs.filecenter.mapper.dsrs.SensitiveLevelMapper;
import com.bwda.dsrs.filecenter.service.SensitiveLevelService;
import com.bwda.dsrs.filecenter.service.SensitiveRuleService;
import com.bwda.dsrs.filecenter.service.SensitiveWordsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 业务配置--敏感等级--服务层实现类
 *
 * @author zhangyinmei
 * @date 2019年4月28日
 */
@Service
public class SensitiveLevelServiceImpl extends BaseServiceImpl<SensitiveLevelPo, SensitiveLevelCondition, SensitiveLevelMapper> implements SensitiveLevelService {

    @Autowired
    private SensitiveRuleService sensitiveRuleService;

    @Autowired
    private SensitiveLevelService sensitiveLevelService;

    @Autowired
    private SensitiveWordsService sensitiveWordsService;

    /**
     * 校验敏感等级规则
     *
     * @param
     * @throws BusinessServiceException
     */
    @Override
    public ResponseEntity checkSensitiveLevelRule(SensitiveLevelUpdateForm form) throws BusinessServiceException {
        ResponseEntity result = new ResponseEntity();
        result.setResult(BusinessConstants.StringConstant.FAIL);
        result.setRescode(BusinessConstants.NumberConstant.FAILRESCODE);
        if (form == null) {
            result.setMsg("未配置敏感字段规则，请配置。");
            return result;
        }
        int sensitiveRel = form.getSensitiveRel();
        //名称、等级、匹配关系不用再次校验了，在form实体类中已校验过了！
        //1.校验 敏感字段是否重复
        List<SensitiveRuleCreateForm> sensitiveRuleStrList = form.getSensitiveRuleCreateFormList();
        if (sensitiveRuleStrList == null || sensitiveRuleStrList.isEmpty()) {
            result.setMsg("未配置敏感字段规则，请配置。");
            return result;
        }

        //名称、等级、匹配关系不用再次校验了，在form实体类中已校验过了！
        //1.校验 敏感字段是否重复
        //定义map,用来记录敏感字段出现的次数，key为敏感字段ID，value为敏感字段被配置的次数。
        Map<Integer, List<SensitiveRuleVo>> ruleSettingMap = new HashMap<Integer, List<SensitiveRuleVo>>(16);

        for (SensitiveRuleCreateForm sensitiveRuleCreateForm : sensitiveRuleStrList) {
            //获取敏感字段ID
            Integer settingWordId = sensitiveRuleCreateForm.getWordId();
            List<SensitiveRuleVo> settingRuleVoList = null;
            if (ruleSettingMap.containsKey(settingWordId)) {
                settingRuleVoList = ruleSettingMap.get(settingWordId);
                SensitiveRuleVo sensitiveRuleVo = CopyUtil.transfer(sensitiveRuleCreateForm, SensitiveRuleVo.class);
                settingRuleVoList.add(sensitiveRuleVo);
                ruleSettingMap.put(settingWordId, settingRuleVoList);
            } else {
                settingRuleVoList = new ArrayList<SensitiveRuleVo>();
                SensitiveRuleVo sensitiveRuleVo = CopyUtil.transfer(sensitiveRuleCreateForm, SensitiveRuleVo.class);
                settingRuleVoList.add(sensitiveRuleVo);
                ruleSettingMap.put(settingWordId, settingRuleVoList);
            }
        }
        //校验用户设置规则是否已经设置，或者出现断层
        for (Integer settingWordId : ruleSettingMap.keySet()) {
            //用户设置的规则
            List<SensitiveRuleVo> settingRuleVoList = ruleSettingMap.get(settingWordId);
            if (settingRuleVoList != null && settingRuleVoList.size() > BusinessConstants.NumberConstant.ONE) {
                result.setMsg("敏感字段【" + querySensitiveWordName(settingWordId) + "】重复配置。");
                return result;
            }
            for (SensitiveRuleVo sensitiveRuleVo : settingRuleVoList) {
                if (sensitiveRuleVo.getMaxTimes() != null && sensitiveRuleVo.getMinTimes() != null && (sensitiveRuleVo.getMinTimes()) > sensitiveRuleVo.getMaxTimes()) {
                    result.setMsg("敏感字段【" + querySensitiveWordName(settingWordId) + "】配置的最多次数小于最少次数。");
                    return result;
                }
                Map<String, String> checkResult = checkWordStandard(sensitiveRel, sensitiveRuleVo);
                //如果不通过
                if (BusinessConstants.CHECK_WORD_NOPASS.equals(checkResult.get("code"))) {
                    result.setMsg(checkResult.get("msg"));
                    return result;
                }
            }
        }
        result.setResult(BusinessConstants.StringConstant.OK);
        result.setRescode(BusinessConstants.NumberConstant.OKRESCODE);
        result.setMsg("校验通过！");
        return result;
    }

    /**
     * //校验敏感字是否有断层，或者重复
     *
     * @param sensitiveRel
     * @param sensitiveRuleVo
     * @return
     */
    private Map<String, String> checkWordStandard(int sensitiveRel, SensitiveRuleVo sensitiveRuleVo) {
        Map<String, String> result = new HashMap<String, String>(16);
        Map<Integer, List<SensitiveRuleVo>> ruleMap = querySettingWords();
        //敏感词记录id
        Integer id = sensitiveRuleVo.getId();
        SensitiveRulePo sensitiveRulePo = sensitiveRuleService.query(id);
        //敏感词id
        Integer settingWordId = sensitiveRuleVo.getWordId();
        //敏感词最小值
        Integer settingMinValue = sensitiveRuleVo.getMinTimes();
        //敏感词最大值
        Integer settingMaxValue = sensitiveRuleVo.getMaxTimes();
        //数据库里设置的规则
        List<SensitiveRuleVo> ruleVoList = ruleMap.get(settingWordId);
        //如果未设置此类敏感词，则无需校验
        if (ruleVoList == null || ruleVoList.size() == BusinessConstants.NumberConstant.ZERO) {
            //未设置或者修改第一条数据
            if (!settingMinValue.equals(BusinessConstants.INTEGER_ONE)) {
                result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】出现的最少次数应该为1.");
                return result;
            } else {
                result.put("code", BusinessConstants.CHECK_WORD_PASS);
                return result;
            }
        }
        //如果是修改，判断敏感字修改，敏感字未修改且有一条记录，则最小值为0
        else if (ruleVoList.size() == BusinessConstants.NumberConstant.ONE && sensitiveRulePo != null && sensitiveRulePo.getWordId().equals(settingWordId)) {
            if (!settingMinValue.equals(BusinessConstants.INTEGER_ONE)) {
                result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】出现的最少次数应该为1.");
                return result;
            }
        } else {
            if (sensitiveRulePo == null) {
                SensitiveRuleVo lastVo = ruleVoList.get(ruleVoList.size() - 1);
                SensitiveLevelPo sensitiveLevelPo = sensitiveLevelService.query(lastVo.getSensitiveId());
                if (sensitiveRel == sensitiveLevelPo.getSensitiveRel()) {
                    //判断当前与上一级是否出现断层
                    if ((settingMinValue - lastVo.getMaxTimes()) > BusinessConstants.NumberConstant.ONE) {
                        result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                        result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】出现次数在区间：【" + lastVo.getMaxTimes() + "," + settingMinValue + "】为断层，请重新配置。");
                        return result;
                    }
                    //判断当前与上一级是否出现交叉
                    if ((lastVo.getMaxTimes() - settingMinValue) >= BusinessConstants.NumberConstant.ZERO) {
                        result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                        result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】参数设置与上级有交叉。");
                        return result;
                    }
                }

            } else {
                for (int e = 0; e < ruleVoList.size(); e++) {
                    //如果修改的已存在的第一条记录且记录多余两条
                    if (e == 0 && ruleVoList.size() > 1) {
                        SensitiveRuleVo currentVo = ruleVoList.get(e);
                        if (currentVo.getId().equals(id)) {
                            //开始最少为0
                            if (!settingMinValue.equals(BusinessConstants.INTEGER_ONE)) {
                                result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                                result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】出现的最少次数应该为1.");
                                return result;
                            }

                            SensitiveRuleVo latterVo = ruleVoList.get(e + 1);
                            SensitiveLevelPo sensitiveLevelPo = sensitiveLevelService.query(latterVo.getSensitiveId());
                            if (sensitiveRel == sensitiveLevelPo.getSensitiveRel()) {
                                if ((settingMaxValue - latterVo.getMinTimes()) >= BusinessConstants.NumberConstant.ZERO) {
                                    result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                                    result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】参数设置与上级有交叉。");
                                    return result;
                                }
                            }
                        }
                    }
                    //只存在两条记录或者最后一条记录 只需与上一级校验
                    boolean flag = (e == 1 && ruleVoList.size() == 2) || (e >= 1 && ruleVoList.size() >= 3 && (e + 1 == ruleVoList.size()));
                    if (flag) {
                        SensitiveRuleVo currentVo = ruleVoList.get(e);
                        if (currentVo.getId().equals(id)) {
                            SensitiveRuleVo previousVo = ruleVoList.get(e - 1);
                            SensitiveLevelPo sensitiveLevelPo = sensitiveLevelService.query(previousVo.getSensitiveId());
                            if (sensitiveRel == sensitiveLevelPo.getSensitiveRel()) {
                                if ((settingMinValue - previousVo.getMaxTimes()) > BusinessConstants.NumberConstant.ONE) {
                                    result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                                    result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】出现断层，请重新配置。");
                                    return result;
                                }
                                if ((previousVo.getMaxTimes() - settingMinValue) >= BusinessConstants.NumberConstant.ZERO) {
                                    result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                                    result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】参数设置与上级有交叉。");
                                    return result;
                                }
                            }
                        }
                    }
                    //如果存在中间层，需校验上一级和下一级
                    if (e >= 1 && ruleVoList.size() >= 3 && (e + 1 < ruleVoList.size())) {
                        SensitiveRuleVo previousVo = ruleVoList.get(e - 1);
                        SensitiveRuleVo currentVo = ruleVoList.get(e);
                        SensitiveRuleVo latterVo = ruleVoList.get(e + 1);
                        if (currentVo.getId().equals(id)) {
                            SensitiveLevelPo psensitiveLevelPo = sensitiveLevelService.query(previousVo.getSensitiveId());
                            if (sensitiveRel == psensitiveLevelPo.getSensitiveRel()) {
                                //判断当前与上一级或者下一级是否出现断层
                                if ((sensitiveRulePo.getMinTimes() - previousVo.getMaxTimes()) > BusinessConstants.NumberConstant.ONE) {
                                    result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                                    result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】出现断层，请重新配置。");
                                    return result;
                                }
                                //判断当前与上一级或者下一级是否出现断层
                                if ((previousVo.getMaxTimes() - sensitiveRulePo.getMinTimes()) >= BusinessConstants.NumberConstant.ZERO) {
                                    result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                                    result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】参数设置与上级有交叉。");
                                    return result;
                                }
                            }
                            SensitiveLevelPo lsensitiveLevelPo = sensitiveLevelService.query(previousVo.getSensitiveId());
                            if (sensitiveRel == lsensitiveLevelPo.getSensitiveRel()) {
                                //判断当前与上一级或者下一级是否出现断层
                                if ((sensitiveRulePo.getMaxTimes() - latterVo.getMinTimes()) >= BusinessConstants.NumberConstant.ZERO) {
                                    result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                                    result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】参数设置与上级有交叉。");
                                    return result;
                                }
                                //判断当前与上一级或者下一级是否出现断层
                                if ((latterVo.getMinTimes() - sensitiveRulePo.getMaxTimes()) > BusinessConstants.NumberConstant.ONE) {
                                    result.put("code", BusinessConstants.CHECK_WORD_NOPASS);
                                    result.put("msg", "敏感字段【" + querySensitiveWordName(settingWordId) + "】出现断层，请重新配置。");
                                    return result;
                                }
                            }
                        }
                    }

                }

            }
        }
        return result;
    }


    /**
     * 获取已经设置的敏感词
     *
     * @return
     */
    private Map<Integer, List<SensitiveRuleVo>> querySettingWords() {
        //查询所有敏感字段出现的次数
        Map<Integer, List<SensitiveRuleVo>> ruleMap = new HashMap<Integer, List<SensitiveRuleVo>>(16);
        SensitiveRuleCondition sensitiveRuleCondition = new SensitiveRuleCondition();
        sensitiveRuleCondition.setDelFlag(BusinessConstants.NumberConstant.ZERO);
        List<SensitiveRulePo> ruleList = sensitiveRuleService.queryRuleList(sensitiveRuleCondition);
        if (ruleList != null && ruleList.size() > 0) {
            for (SensitiveRulePo sensitiveRulePo : ruleList) {
                Integer wordId = sensitiveRulePo.getWordId();
                List<SensitiveRuleVo> ruleVoList = null;
                if (ruleMap.containsKey(wordId)) {
                    ruleVoList = ruleMap.get(wordId);
                    SensitiveRuleVo sensitiveRuleVo = CopyUtil.transfer(sensitiveRulePo, SensitiveRuleVo.class);
                    ruleVoList.add(sensitiveRuleVo);
                    ruleMap.put(wordId, ruleVoList);
                } else {
                    ruleVoList = new ArrayList<SensitiveRuleVo>();
                    SensitiveRuleVo sensitiveRuleVo = CopyUtil.transfer(sensitiveRulePo, SensitiveRuleVo.class);
                    ruleVoList.add(sensitiveRuleVo);
                    ruleMap.put(wordId, ruleVoList);
                }
            }
        }
        return ruleMap;
    }

    private String querySensitiveWordName(Integer sensitiveWordId) {
        String result = "";
        SensitiveWordsPo sensitiveWordsPo = sensitiveWordsService.query(sensitiveWordId);
        if (sensitiveWordsPo != null) {
            result = sensitiveWordsPo.getName();
        }
        return result;
    }

    /**
     * 根据敏感扫描结果查询所属敏感等级
     *
     * @param sensitiveWordsMap
     * @return
     * @throws BusinessServiceException
     */
    @Override
    public Integer querySensitiveLevel(Map<Integer, Integer> sensitiveWordsMap) throws BusinessServiceException {
        //默认敏感等级为1
        Integer result = BusinessConstants.NumberConstant.ONE;
        //1.在用的
        //2.根据map的长度去查，如果共是一，去查询关系为或的，或者关系为且只有一个关键字段的

        //判断map长度
        int mapSize = sensitiveWordsMap.size();
        if (mapSize == BusinessConstants.NumberConstant.ZERO) {
            //为空则匹配等级为0;
            return result;
        } else {
            //TODO 获取敏感等级（从高到低）,这里把被禁用的也查出来了
            SensitiveLevelCondition sensitiveLeveCondition = new SensitiveLevelCondition();
            sensitiveLeveCondition.setSensitiveState(BusinessConstants.NumberConstant.ZERO);
            sensitiveLeveCondition.setDelFlag(BusinessConstants.NumberConstant.ZERO);
            List<SensitiveLevelPo> list = this.querySensitiveLevelList(sensitiveLeveCondition);
            if (list == null || (list.size() == BusinessConstants.NumberConstant.ZERO)) {
                throw new BusinessServiceException("未配置敏感等级。");
            }
            for (SensitiveLevelPo sensitiveLevelPo : list) {

                if (sensitiveLevelPo.getSensitiveState().equals(BusinessConstants.SensitiveLevelState.INVALID)) {
                    continue;
                }
                //敏感策略是0:与 & 1:或
                Integer sensitiveRel = sensitiveLevelPo.getSensitiveRel();
                //查询当前敏感等级设置的敏感词
                SensitiveRuleCondition ruleCondition = new SensitiveRuleCondition();
                ruleCondition.setSensitiveId(sensitiveLevelPo.getId());
                List<SensitiveRulePo> ruleList = sensitiveRuleService.queryList(ruleCondition);
                //控制文件是否匹配此敏感等级(或的情况)
                Boolean matchFlag = false;
                //控制文件是否匹配此敏感等级(与的情况)
                Integer matchSize = 0;
                for (SensitiveRulePo sensitiveRulePo : ruleList) {
                    Integer scanTime = sensitiveWordsMap.get(sensitiveRulePo.getWordId());
                    if (scanTime == null) {
                        scanTime = 0;
                    }

                    //如果条件为或，有一个匹配上则文件属于此敏感等级
                    boolean flag = (scanTime >= sensitiveRulePo.getMinTimes() && scanTime <= sensitiveRulePo.getMaxTimes()) && sensitiveRel.equals(BusinessConstants.INTEGER_ONE);
                    if (flag) {
                        matchFlag = true;
                    }
                    //如果条件为与，有一个匹配上则文件属于此敏感等级
                    boolean flag2 = (scanTime >= sensitiveRulePo.getMinTimes() && scanTime <= sensitiveRulePo.getMaxTimes()) && sensitiveRel==0;
                    if (flag2) {
                        matchSize++;
                    }
                }
                if (matchFlag || matchSize.equals(ruleList.size())) {
                    return sensitiveLevelPo.getSensitiveLevel();
                }
            }
        }
        return result;
    }


    /**
     * 获取敏感等级（从高到低）
     *
     * @param condition
     * @return
     */
    public List<SensitiveLevelPo> querySensitiveLevelList(SensitiveLevelCondition condition) {
        return this.getMapper().querySensitiveLevelList(condition);
    }


}